perm filename WING[0,BGB] blob
sn#073902 filedate 1973-11-29 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00017 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00006 00002 A SUMMARY OF WINGED EDGE OPERATIONS.
C00058 00003 The Winged Edge Operations.
C00063 00004 MIDPOINT EXAMPLE (see text on page 20).
C00065 00005 The Wing Link Operation.
C00070 00006 Part Tree Operations (continued).
C00074 00007 The Perimeter Fetch Operations.
C00078 00008 Euler Primitives.
C00099 00009 TWO EXAMPLES USING EULER PRIMITIVES. (see page 30).
C00102 00010 4. ENEW ← MKFE(V1,F,V2)
C00107 00011 Euler Primitives. (Continued).
C00112 00012 SOLID PRIMITIVES.
C00121 00013
C00125 00014 IMAGE PRIMITIVES.
C00128 00015
C00132 00016 GEOMED - a drawing program.
C00136 00017
C00143 ENDMK
C⊗;
A SUMMARY OF WINGED EDGE OPERATIONS.
DYNAMIC STORAGE ALLOCATION.
1. Q ← MKNODE(SIZE);
2 KLNODE(Q);
BFEV MAKE & KILL OPERATIONS.
1. BNEW ← MKB(B); KLB(BNEW);
2. FNEW ← MKF(B); KLF(B,FNEW);
3. ENEW ← MKE(B); KLE(B,ENEW);
4. VNEW ← MKV(B); KLV(B,VNEW);
FETCH LINK AND STORE LINK OPERATIONS.
1. F ← NFACE(Q); F ← PFACE(Q); NFACE.(F,Q); PFACE.(F,Q);
2. E ← NED(Q); E ← NED(Q); NED.(E,Q); PED.(E,Q);
3. V ← NVT(Q); V ← NVT(Q); NVT.(V,Q); PVT.(V,Q);
4. A ← NCW(E); A ← PCW(E); NCW.(A,E); PCW.(A,E);
5. A ← NCCW(E); A ← PCCW(E); NCCW.(A,E); PCCW.(A,E);
WING LINK OPERATIONS.
1. WING(E1,E2);
2. INVERT(E);
PERIMETER FETCH OPERATIONS.
1. E ← ECW(E,Q);
2. E ← ECCW(E,Q);
3. F ← FCW(E,V);
4. F ← FCCW(E,V);
5. V ← VCW(E,F);
6. V ← VCCW(E,F);
7. Q ← OTHER(E,Q);
PARTS TREE OPERATIONS.
1. B ← PART(B); B ← COPART(B);
2. B ← BODY(Q); B ← SUPART(B);
3. ATT(B1,B2); ATTACH(B1,B2);
4. DET(B); DETACH(B);
The Winged Edge Operations.
BFEV Make & Kill Operations.
Just above the free storage routines are the four pairs of
make and kill operations. The MKB operation creates a body block and
attaches it as a sub-part of the given body. The world body always
exists so that MKB(WORLD) will make a body attached to the world. In
this paper, the terms `attach' and `detach' refer to operations on
the parts-tree linkages. The FEV make operations: MKF, MKE, MKV
create the corresponding FEV entities and place them in their
respective FEV rings of the given body. In the current
implementation, the FEV makers set the type bits of the entity, and
increment the proper total FEV counter, as well as the proper body
FEV counter in the given body's node, (the Fcnt, Ecnt, Vcnt node
positions are shown in figure 2.3). The kill operations: KLB, KLF,
KLE, and KLV; delete the entity from its ring (or remove it from the
parts-tree), release its space by calling RELBLK, and then decrement
the appropriate counters. The body of the entity is needed by the
kill primitives and can be provide directly as an argument or if
missing, will be found in the data by the primitive itself.
Fetch Link and Store Link Operations.
Each of the fetch link and store link operations named in the
summary is a single machine instruction that accesses the
corresponding link position in a node. Once BFEV nodes exist, with
their rings and parts-tree already in place; the fetch and store link
operations are used to construct or modify a polyhedron's surface. At
this lowest level, constructing a polyhedron requires three steps:
first the two vertex and two face pointers are placed into each edge
in counter clockwise order as they appear when that edge is viewed
from the exterior of the solid; second an edge pointer is placed in
each face and vertex, so that one can later get from a given face or
vertex to one of its edges; and third the edge wings are linked so
that all the ordered perimeter accessing operations described below
will work. Wing linking is facilitated by the WING operation.
MIDPOINT EXAMPLE (see text on page 20).
\ pvt /
\ /
nccw \ / pcw
\ /
V ⊗
|
ENEW |
| nvt
VNEW ⊗
| pvt
E |
|
⊗
/ \
ncw / \ pccw
/ \
/ nvt \
INTEGER PROCEDURE MIDPOINT (INTEGER E);
BEGIN "MIDPOINT"
INTEGER B,ENEW,VNEW,V1,V2;
α CREATE A NEW EDGE AND VERTEX;
B ← BODY(E);
VNEW ← MKV(B);
ENEW ← MKE(B);
α GET VERTICES AND FACES CONNECTED TO EDGES;
PVT.(PVT(E),ENEW);
PVT.(VNEW,E);
NVT.(VNEW,ENEW);
PFACE.(PFACE(E),ENEW);
NFACE.(NFACE(E),ENEW);
α GET EDGES CONNECTED TO VERTICES;
IF PED(V)=E THEN PED.(ENEW,V);
PED.(ENEW,VNEW);
α LINK THE WINGS TOGETHER;
WING(NCCW(E),ENEW);WING(PCW(E),ENEW);
NCW.(E,ENEW);PCCW.(E,ENEW);
PCW.(ENEW,E);NCCW.(ENEW,E);
α PLACE VNEW AT MIDPOINT POSITION;
V1 ← PVT(ENEW); V2 ← NVT(E);
XWC(VNEW) ← (XWC(V1)+XWC(V2)) * 0.5;
YWC(VNEW) ← (YWC(V1)+YWC(V2)) * 0.5;
ZWC(VNEW) ← (ZWC(V1)+ZWC(V2)) * 0.5;
RETURN(VNEW);
END "MIDPOINT";
The Wing Link Operation.
The WING operation stores edge pointers into edges so that
the face perimeters and vertex perimeters are made; and so that
surface parity is preserved. Given two edges which have a vertex and
a face in common, the WING operation places the first edge in the
proper relationship (PCW, NCCW, NCW, or PCCW) with respect to the
second, and the second in the proper relationship with respect to the
first. The INVERT operation swaps the vertex, face, clockwise wing,
and counter clockwise wing pointers of an edge. INVERT preserves
surface parity, but flips edge parity.
The Midpoint Example.
In figure 2.4 an example of how the operations given so far
could be used to code a midpoint primitive is shown. The example
midpoint primitive takes an edge argument and splits it in two by
making a new edge and a new vertex and by placing them into the
polyhedron with the topology shown in the diagram. Then the midpoint
locus is computed and the new vertex is return. The ALGOL notation
used is SAIL, which allows defining the character "α" as a COMMENT
delimiter and allows defining XWC as a real number from the special
array named MEMORY. The MEMORY array in SAIL is the job's actual
machine memory space and gives the user the freedom of accessing any
word in his core image.
The Parts-Tree Operations.
As shown in figure 2.1, each body node has two parts-tree
links named PART and COPART. The PART link is the head of a list of
sub-parts of the body. When a body has no sub-parts the PART link is
the negative of that body's pointer; that is the body points at
itself. When a body has parts, the first part is pointed at by PART
and the second is pointed at by the COPART link of the first and so
on until a negative pointer is retrieved which indicates the end of
the parts list. The negative pointer at the end of a parts list
points back to the orginal body, which is the supra-part or "supart"
of all those bodies in that list.
The parts may be accessed by its link names PART and COPART.
Also the SUPART of a body returns the (positive) pointer to the
supart of a body. The BODY operation returns the body to which a face
edge or vertex belongs; this might be found by CDR'ing a FEV ring
until a body node is reached, but for the sake of speed each edge (as
shown in figure 2.3) has a PBODY link which points back to the body
to which the edge belongs, and since each face and vertex points at
an edge, the body of an FEV entity can be retrieved by fetching only
one or two links.
Part Tree Operations (continued).
The parts-tree is altered by the DET(B) operation which
removes a body B from its supart and leaves it hanging free; and the
ATT(B1,B2) operation which places a free body B1 into the parts list
of a body B2. Since bodies are made attached to the world body and
generally kept attached to something, two further parts-tree
operations are provided, compounding the first two in the necessary
manner. The DETACH(B) operation DET's B from its current owner and
ATT's it to the world; and the ATTACH(B1,B2) operation will DET B1
from its supart and attach it to a new supart. In normal (one world)
circumstances one only needs to use ATTACH to build things.
Perimeter Fetch and Store Operations.
There are seven perimeter fetch primitives, which when given
an edge and one of its links will fetch another link in a certain
fashion. Using the winged edge data structure these primitives are
easily implemented in a few machine instructions which test the type
bits and typically do one or two compares. Clockwise and counter
clockwise are always determined from the outside of a polyhedron
looking down on a particular face, edge or vertex. I apologize for
the high redundancy on the next page, but felt that it was necessary
to make the explanations independent for reference.
FIGURE 2.5 - Face Perimeter Accessing with respect to edge E.
VCCW(E,F) ⊗-------E-------⊗ VCW(E,F)
\ /
\ F /
ECCW(E,F) ECW(E,F)
\ /
\ /
\ /
\ /
⊗
FIGURE 2.6 - Vertex Perimeter Accessing with respect to edge E.
E
|
|
FCCW(E,V) | FCW(E,V)
⊗ V
/ \
/ \
/ \
/ \
ECCW(E,V) ECW(E,V)
The Perimeter Fetch Operations.
E ← ECW(E,F); Get Edge Clockwise from E about F's perimeter.
E ← ECCW(E,F); Get Edge Counter Clockwise from E about F's perimeter.
Given an edge and a face belonging to that edge, the ECW
fetch primitive returns the next edge clockwise belonging to the
given face's perimeter and the ECCW fetch primitive returns the next
edge counter clockwise belonging to the given face's perimeter.
E ← ECW(E,V); Get Edge Clockwise from E about V's perimeter.
E ← ECCW(E,V); Get Edge Counter Clockwise from E about V's perimeter.
Given an edge and a vertex belonging to that edge, the ECW
fetch primitive returns the next edge clockwise belonging to the
given vertex's perimeter and the ECCW fetch primitive returns the
next edge counter clockwise belonging to the given vertex's
perimeter.
F ← FCW(E,V); Get the face clockwise from E about V.
F ← FCCW(E,V); Get the face counter clockwise from E about V.
Given an edge and a vertex belonging to that edge, the FCW
fetch primitive returns the face clockwise from the given edge about
the given vertex and the FCCW fetch primitive returns the face
counter clockwise from the given edge about the given vertex.
V ← VCW(E,F); Get the vertex clockwise from E about F.
V ← VCCW(E,F); Get the vertex counter clockwise from E about F.
Given an edge and a face belonging to that edge, the VCW
fetch primitive returns the vertex clockwise from the given edge
about the given face and the VCCW fetch primitive returns the vertex
counter clockwise from the given edge about the given face.
F ← OTHER(E,F); Get the other face of an edge.
V ← OTHER(E,V); Get the other vertex of an edge.
Given an edge and one face of that edge the OTHER fetch
primitive returns the other face belonging to that edge. Given an
edge and one vertex of that edge the OTHER fetch primitive returns
the other vertex belonging to that edge.
Euler Primitives.
1. BNEW ← MKBFV; Make Seminal Body.
The MKBFV primitive returns a body with one face and one
vertex and no edges. Other bodies are formed by applying primitives
to the seminal MKBFV body. The seminal body is initially attached as
a part of the world.
2. KLBFEV(BNEW); Kill Body and all its pieces.
The KLBFEV primitive will detach and delete from memory the
body given as an argument as well as all its faces, edges, vertices
and sub-parts.
3. VNEW ← MKEV(F,V); Make an edge and a vertex.
The MKEV primitive takes a face, F, and a vertex, V, of F's
perimeter and it creates a new edge, ENEW, and a new vertex, VNEW.
ENEW and VNEW are called a "wire spur" at V on F. MKEV returns the
newly made vertex, VNEW; ENEW can be reached since PED(VNEW) is
always ENEW. Only one wire spur is allowed at V on F at a time.
When applied to the face of a seminal body, MKEV forms the
special polyhedron called a "wire" and returns the new vertex as the
"negative" end of the wire. A wire polyhedron is illustrated in
figure 3.1. When applied to the negative end of a wire, MKEV extends
the wire; however if applied to any other vertex of the wire, MKEV
refuses to change anything and merely returns its vertex argument.
Figure 3.1 - A Wire Polyhedron. Figure 3.2 - VNEW←MKEV(F,V);
seminal vertex ⊗ V1 +V
positive end +| of wire. /|\
| E1 / |←←←←ENEW spur.
-| / | \
⊗ V2 / -VNEW \
+| / \
| E2 / F \
negative end -| of wirer / \
latest vertex ⊗ V3 ⊗---------------⊗
TWO EXAMPLES USING EULER PRIMITIVES. (see page 30).
α MAKE A CUBE;
INTEGER PROCEDURE MKCUBE;
BEGIN "MKCUBE"
INTEGER B,F,E,V1,V2,V3,V4;
α CREATE SEMINAL POLYHEDRON;
B ← MKBFV; F ← PFACE(B); V1 ← PVT(B);
XWC(V1)←+1; YWC(V1)←+1; ZWC(V1)←-1;
α MAKE SEMINAL POLYHEDRON INTO A LAMINA POLYHEDRON;
V2 ← MKEV(F,V1); XWC(V2)←-1;
V3 ← MKEV(F,V2); YWC(V3)←-1;
V4 ← MKEV(F,V3); XWC(V4)←+1;
F ← MKFE(V1,F,V4);
α MAKE FOUR SPURS ON THE LAMINA;
V1 ← MKEV(F,V1); ZWC(V1)←+1;
V2 ← MKEV(F,V2);
V3 ← MKEV(F,V3);
V4 ← MKEV(F,V4);
α JOIN SPURS TO FORM FINAL FACES;
E ← MKFE(V1,F,V2);
E ← MKFE(V2,F,V3);
E ← MKFE(V3,F,V4);
E ← MKFE(V4,F,V1);
RETURN(B);
END "MKCUBE";
α FORM A PYRAMID ON A FACE;
INTEGER PROCEDURE PYRAMID (INTEGER F);
BEGIN "PYRAMID"
INTEGER V,V0,E,E0,PEAK,EX;
REAL X,Y,Z; INTEGER I;
X←Y←Z←I←0;
α GET A VERTEX OF THE FACE AND MAKE A SPUR TO A PEAK;
E←E0←PED(F);
V0 ← VCW(E0,F);
PEAK ← MKEV(F,V0);
α CONNECT THE OTHER VERTICES OF THE FACE TO THE PEAK;
WHILE TRUE DO
BEGIN
V ← VCCW(E,F);
X←X+XWC(V); Y←Y+YWC(V); Z←Z+ZWC(V);
INCREM(I);
IF V=V0 THEN DONE;
E ← ECCW(E,F);
EX ← MKFE(PEAK,F,V);
END;
α POSITION THE PEAK VERTEX AT THE CENTER OF THE FACE;
XWC(PEAK)←X/I; YWC(PEAK)←Y/I; ZWC(PEAK)←Z/I;
RETURN(PEAK);
END "PYRAMID";
4. ENEW ← MKFE(V1,F,V2);
The MKFE primitive can be thought of as a face split. Given
a face and two of its vertices, MKFE forms a new face on the
clockwise side of the line V1 to V2 leaving the old face on the
counter clockwise side. V1 becomes the PVT of ENEW, V2 becomes the
NVT of ENEW, F becomes the PFACE of ENEW and FNEW becomes the NFACE
of ENEW; also ENEW becomes the PED of F and FNEW.
Figure 3.3 - MKFE and KLFE.
BEFORE MKFE AFTER ENEW←MKFE(V1,F,V2)
⊗ ⊗ ⊗ ⊗
/ \ / \ / \ / \
/ \ / \ / \ / \
/ \ / \ / \ / \
/ ⊗ \ / +V1 \
/ \ / -FNEW | +F \
⊗ F ⊗ ⊗ |←←←ENEW ⊗
\ / \ | /
\ ⊗ / \ -V2 /
\ / \ / \ / \ /
\ / \ / \ / \ /
\ / \ / \ / \ /
⊗ ⊗ ⊗ ⊗
AFTER F←KLFE(ENEW); BEFORE KLFE
MKFE is also used to join the two ends of a wire polyhedron
to form a "lamina"; or the two ends of wire spurs to split a face; or
an end of a wire spur and a regular perimeter vertex to split a face.
A "lamina polyhedron" has only two faces and thus no volume.
EULER EXAMPLES.
The use of the primitives discussed so far is illustrated by
the example subroutines in figure 3.4 on page 29. The make cube
subroutine starts by placing a seminal vertex at (1,1,1); Then a wire
of three edges is made using the MKEV primitive. As the code implies,
MKEV places its new vertex at the locus of the old one. The ends of
the wire are joined with a MKFE to form a lamina polyhedron, then a
spur is placed on each of the vertices of the lamina, and finally the
spurs are joined.
The pyramid example is more realistic, since polyhedra are
not generated ex nihil, but rather arise out of the vision routines
and the geometric editor. PYRAMID takes a face as an argument (which
is assumed to have no spurs) and runs a spur from one vertex to the
middle of the faces, then all the remaining vertices of the face are
joined to that spur to form a pyramid.
Euler Primitives. (Continued).
5. VNEW ← ESPLIT(E); Edge Split.
This primitive splits an edge by making a new vertex and a
new edge. Its implementation is very similar to the midpoint example
on page 19. ESPLIT is heavily used in the hidden line eliminator.
6. F ← KLFE(ENEW); Kill Face Edge.
This primitive Kills a face and an edge leaving one face.
Since this primitive is intended to be an inverse of MKFE, the NFACE
of ENEW is killed. However the NFACE and PFACE of an edge may be
swapped by using the INVERT(E) primitive. See Figure 3.3 for KLFE.
7. E ← KLEV(VNEW); Kill Edge Vertex.
This primitive kills an edge and a vertex leaving one edge.
This primitive will eliminate spurs made with MKEV and midpoints made
with ESPLIT; in a pure form it would have to leave vertices with a
valence greater than two untouched, however it in fact "un-pyramids"
them with a series of KLFE's and then kills the remaining spur.
8. V ← KLVE(ENEW); Kill Vertex Edge.
This primitive kills a vertex and an edge leaving one vertex.
This primitive is the face-vertex dual of KLFE, namely instead of
killing NFACE of E and fixing up PFACE's perimeter, KLEV kills the
NVT of E and fixes up PVT of E's perimeter.
9. B ← GLUE(F1,F2); Glue two faces.
This primitive glues two faces together forming one new body
out of two old ones (the body of F1 survives) or forming a handle on
the given body. The number of edges in the two faces must be the same
and their orientation should be opposite (exterior to exterior).
*10. BNEW ← UNGLUE(E); Unglue along seam. *not implemented.
This primitive unglues along the seam containing E. The
UNGLUE primitive requires that a loop of edges be marked as a "seam"
along which unglue will form two opposite faces. The marks are made
in the temporary type bit in the edge nodes of the given body. If
the cut forms two disjoint bodies then a new body is made on the
NFACE side of the original E argument.
SOLID PRIMITIVES.
1. VPEAK ← PYRAMID(F);
2. F ← PRISM(F);
3. F ← CWPRISMIOD(F);
4. F ← CCWPRISMIOD(F);
These four primitives are called the "sweep primitives",
because they form a simple polyhedron from a face in a fashion that
appears like sweeping the face along. The sweep primitives (with the
exception of PYRAMID) do not change the location of the given face
but merely copy its perimeter, forming new faces and edges between
the old perimeter and the new perimeter. The pyramid primitive has
already appeared as an example on page 29.
Starting with a nine sided face lamina, the rocket in figure
3.5 was formed from the bottom by sweeping two prism stages, then two
counter clockwise prismoid stages, and then two clockwise prismoid
stages, and finally one pyramid to form the nose cone. The fins were
made by prism sweeping every third face of the first stage.
5. ROTCOM(F); Rotation Completion.
As illustrated in the first three frames of figure 3.7 below,
wire faces can be swept to form a shell. When a wire face is swept by
a sweep primitive (other than pyramid) it is marked as a shell face
of rotation and its original perimeter count is kept for later sweeps
to refer to. In the third frame the shell has been positioned so
that its slot can be seen. The shell face now includes all the edges
of both pole caps as well as the two meridians of the slot. ROTCOM
takes such a shell face and breaks it into two polar faces and as
many other faces as necessary, by means of the count that was saved.
6. FVDUAL(B);
7. BNEW←MKCOPY(B);
These two primitives illustrate the extremes from a class of
miscellaneous primitives. FVDUAL is a worthless curosity and MKCOPY
is quite useful but uninteresting. FVDUAL(B) of a body changes all
the faces of a body into vertices and all the vertices into faces, in
the winged edge data structure this merely requires computing a locus
for each face (its center), re-"typing" faces and vertices, and then
swapping the face and vertex link positions in each face, edge and
vertex of the body.
Figure 3.8 illustrates Euclid's construction of a
dodecahedron from a cube. The unit cube is formed, then all its edges
are midpointed and translated 0.2 units into the three pairs of
parallel faces; then the midpoints are lifted 0.3 units off the plane
of each face of the cube; then MKFE is applied six times to split the
eight sided faces into five sided faces; giving a dodecahedron
(nearly regular). Applying the FVDUAL to the dodecahedron yields the
icosahedron.
8. EVERT(B);
9. B1←BUN(B1,B2);
10. B1←BIN(B1,B2);
These three primitives perform the Boolean operations on
polyhedron interior volumes. EVERT(B) turns a body inside out, thus
changing a cube into a room, as a solid into a bubble. Objects with
infinite "interiors" are permissible; such polyhedra are impossible
in many classical developements of solid Geometry which make the
interior of a polyhedron to be the region of space with finite
volume, by definition. The body union is BUN, which allows B1 to
survive if the interiors of the bodies are not disjoint. A body with
two disjoint polyhedrons is shunned. The body intersection is BIN,
which allows B1 to survive if the interiors of the bodies are not
disjoint.
IMAGE PRIMITIVES.
1. PROJECTOR(CAMERA,WORLD);
2. ELIST←CLIPER(WINDOW,WORLD);
3. OCCULT(WORLD);
* 4. SHADOW(SUN,WORLD);
* 5. TV ← MKVID(WINDOW,WORLD);
* 6. B2D ← MKB2D(WINDOW,WORLD);
* 7. B2D ← CAREYE(TV);
The single application around which the geometric modeling
of this paper is being built is for a computer television vision
system for looking at real world scenes. I believe that a
computer must have a means of representing what it is intended to
see and further that the representation must have (in principle) an
inverse relation to a television image. My first premise is rarely
questioned, the second premise is frequentlty questioned.
One
alternative position is that so called "features" can be extracted
from an image and then used by a heuristic problem solver to find an
association between the perceived features and previous general
knowledge; it is then stated that there is no need to go from the
general knowledge or even from the so called image "features" back
down to a television image, even just in principle. I wish to state
the opposite, there is a need to go from the general representation
to a television image in order to develop computer vision without
having to solve several other problems of Artificial Intelligence.
Applications of geometric modeling other than television vision
might include: architectural design, computer animation, and
mechanical drawing.
GEOMED - a drawing program.
GEOMED, Geometric Model Editor, is for making and editing
polyhedra. The command language of GEOMED provides the Euler
primitives in the context of a push down stack (the PADPDL) of
bodies, faces, edges and vertices. The main difference between an
interactive program and a programming language being that the former
carries along a working context so that most arguments and data do
not have to be explicitly named.
V - make seminal vertex body.
E - make edge and vertex.
J - make edge and face.
G - glue two faces.
In addition to the stack, GEOMED provides frames of reference
for the Euclidean transformations; there is a world frame, body
frames, camera frames, relative frame and face frames. Also the
strength of a Euclidean transformation can be halved or double, set
directly or entered numerically in several kinds of units. And
finally the transformation can be done once or repeatedily by keying
chords of Stanford's extra shift keys named "control" and "meta" with
a ; : ( ) - or * character. These characters are not mnemonics but
were chosen because of thier positions on the keyboard.
: ; - transform about X-axis.
( ) - transform about Y-axis.
- * - transform about Z-axis.
no shifts - TRANSLATION.
α - control - ROTATION.
β - meta - DILATION.
ε - meta-control - REFLECTION.
Finally, GEOMED provides access to all the solid primitives
and hidden line elimination, along with commands for the stack,
input, output, display, and switch toggling. The commands are
detailed in the operating note, SAILON-68, along with a list of
GEOMES and GEOMEL subroutines. Two examples should suffice to
illustrate how concise and illegible GEOMED command strings are:
1. V:)\E;E(E:J↑/*S-↑ forms a cube.
2. V:@E*E*E*E*E*E*E*J↑!
\\:@S)S)S)S)S)S)S)S)G↑ forms a torus.
Thus a polyhedron can be represented in a few characters (which must
be compiled); one might hope that such a "representation by
generation" could provide a link between semantic and geometric
models. The hard direction is to get from a polyhedron model to the
command string.